﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using MovieModel.Model.Common;

namespace MovieBuddy.Views.ItemListView
{
    /// <summary>
    /// Interaction logic for ItemList.xaml
    /// </summary>
    public class ItemList<T> : UserControl where T : MovieItem<T>, new()
    {
        private readonly ListView listView;

        public ItemList()
        {
            listView = new ListView();
            listView.SelectionChanged += ListViewSelectionChanged;
            AddChild(listView);
        }

        void ListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SelectionChanged != null) SelectionChanged(this, e);
        }

        public event EventHandler<SelectionChangedEventArgs> SelectionChanged;

        public ItemListItem<T>[] SelectedItems
        {
            get
            {
                return listView.SelectedItems.Cast<ItemListItem<T>>().ToArray();
            }
        }

        public void ClearSelection()
        {
            listView.UnselectAll();
        }

        public IEnumerable<MovieItem<T>> Items
        {
            set
            {
                var newValues = value.OrderBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
                int existingIndex = 0;
                int newIndex = 0;
                while (newIndex < newValues.Count || existingIndex < listView.Items.Count)
                {
                    var existingItem = (ItemListItem<T>) (listView.Items.Count <= existingIndex ? null : listView.Items[existingIndex]);
                    MovieItem<T> newItem = newValues.Count <= newIndex ? null : newValues[newIndex];

                    if (newItem == null)
                    {
                        // we have run out of new items, thus this one can't be in that list
                        listView.Items.RemoveAt(existingIndex);
                        // since we removed an item, no need to increment existing index.
                        continue;
                    }
                    if (existingItem == null)
                    {
                        // we have run out of existing items, so add to the end
                        listView.Items.Add(new ItemListItem<T>(newItem));
                        newIndex++;
                        existingIndex++;
                        continue;
                    }

                    int compare = string.Compare(newItem.Name, existingItem.Item.Name, StringComparison.CurrentCultureIgnoreCase);
                    if (compare < 0)
                    {
                        // insert new item into existing item
                        listView.Items.Insert(existingIndex, new ItemListItem<T>(newItem));
                        existingIndex++;
                        newIndex++;
                    }
                    else if (compare > 0)
                    {
                        // remove existing item
                        listView.Items.RemoveAt(existingIndex);
                    }
                    else // compare == 0
                    {
                        // item exists, leave it and increment both
                        existingIndex++;
                        newIndex++;
                    }
                }
            }
            get { return listView.Items.Cast<ItemListItem<T>>().Select(i => i.Item); }
        }

        public ItemListItem<T> AddItem(MovieItem<T> item)
        {
            int index = 0;
            foreach (ItemListItem<T> i in listView.Items)
            {
                if (string.Compare(i.Item.Name, item.Name, StringComparison.CurrentCultureIgnoreCase) >= 0) break;
                index++;
            }
            var listItem = new ItemListItem<T>(item);
            listView.Items.Insert(index, listItem);
            return listItem;
        }
    }
}
